﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using SmallBusinessKit.DataAccess.Interfaces;
using SmallBusinessKit.Domains;
using SmallBusinessKit.Interfaces;
using SmallBusinessKit.Models.Entities;

namespace SmallBusinessKit.Tests.Domains
{
    /// <summary>
    /// Unit Tests for SmallBusinessDomain Logic
    /// </summary>
    /// <remarks>
    /// Loading the data from an external file for ease 
    /// </remarks>
    [TestClass]
    public class SmallBusinessDomainTests : UnitTestBase
    {
        #region Properties

        private Mock<ICategoryRepository>       _moqCategoryRepository;
        private Mock<IItemRepository>           _moqItemRepository;
        private Mock<IPersonRepository>         _moqPersonRepository;
        private Mock<INewsRepository>           _moqNewsRepository;
        private Mock<ITestimonialRepository>    _moqTestimonialRepository;

        private ISmallBusinessDomain            _domain;

        #endregion Properties

        #region Tests

        [TestInitialize]
        public override void Setup()
        {
            base.Setup();

            _moqPersonRepository        = new Mock<IPersonRepository>();
            _moqCategoryRepository      = new Mock<ICategoryRepository>();
            _moqItemRepository          = new Mock<IItemRepository>();
            _moqNewsRepository          = new Mock<INewsRepository>();
            _moqTestimonialRepository   = new Mock<ITestimonialRepository>();
            
            _domain                     = new SmallBusinessDomain(_moqCategoryRepository.Object, _moqItemRepository.Object, _moqPersonRepository.Object, _moqNewsRepository.Object, _moqTestimonialRepository.Object);
            
            // category data
            var categories              = XmlData.ParseCategories();
            var category                = categories.FirstOrDefault(i => i.Id == "c11");
            var selectedCategories      = categories.Where(i => i.ParentId == null && i.IsVisible).ToList();
            _moqCategoryRepository.Setup(m => m.GetMany(It.IsAny<Expression<Func<Category, bool>>>())).Returns(selectedCategories);
            _moqCategoryRepository.Setup(m => m.Get(It.IsAny<Expression<Func<Category, bool>>>())).Returns(category);

            // item data
            var items = XmlData.ParseItems();
            _moqItemRepository.Setup(m => m.Get(It.IsAny<Expression<Func<Item, bool>>>())).Returns(items.FirstOrDefault(i => i.Id == "02"));

            // people data
            var people = XmlData.ParsePeople();
            var qry    = people.AsQueryable().OrderBy(i => i.Id);
            _moqPersonRepository.Setup(m => m.GetAsQueryable()).Returns(qry);
            //_moqPersonRepository.Setup(m => m.GetById("02")).Returns(people[1]);
            //_moqPersonRepository.Setup(m => m.Get(It.IsAny<Expression<Func<Person, bool>>>())).Returns(people[1]);
            _moqPersonRepository.Setup(m => m.GetMany(It.IsAny<Expression<Func<Person, bool>>>())).Returns(people);

            // news data
            var news = XmlData.ParseNews();
            _moqNewsRepository.Setup(m => m.GetAll()).Returns(news);
            _moqNewsRepository.Setup(m => m.GetById(It.IsAny<string>())).Returns(news[1]);
            _moqNewsRepository.Setup(m => m.Get(It.IsAny<Expression<Func<News, bool>>>())).Returns(news[1]);
            _moqNewsRepository.Setup(m => m.GetMany(It.IsAny<Expression<Func<News, bool>>>())).Returns(news);

            // testimonials data
            var testimonials = XmlData.ParseTestimonials();
            _moqTestimonialRepository.Setup(m => m.GetAll()).Returns(testimonials);
            _moqTestimonialRepository.Setup(m => m.GetById("02")).Returns(testimonials[1]);
            _moqTestimonialRepository.Setup(m => m.Get(It.IsAny<Expression<Func<Testimonial, bool>>>())).Returns(testimonials[2]);
            _moqTestimonialRepository.Setup(m => m.GetMany(It.IsAny<Expression<Func<Testimonial, bool>>>())).Returns(testimonials);
        }

        [TestMethod]
        public void GetCategories()
        {
            // Act
            var results = _domain.GetCategories(null);

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results, typeof(IEnumerable<Category>));
            Assert.AreEqual(5, results.Count());
        }

        [TestMethod]
        public void GetChildItems()
        {
            // Act
            var results = _domain.GetChildItems("c11");

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results, typeof(IEnumerable<Item>));
            Assert.AreEqual(3, results.Count());
        }

        [TestMethod]
        public void GetItem()
        {
            // Act
            var result = _domain.GetItem("02");

            // Assert
            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(Item));
            Assert.AreEqual("Felis Non Purus", result.Title);
        }

        [TestMethod]
        public void GetAllPersons()
        {
            // Act
            var results = _domain.GetAllPersons().ToList();

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results, typeof(IEnumerable<Person>));
            Assert.AreEqual(12, results.Count());
        }

        [TestMethod]
        public void GetAllNews()
        {
            // Act
            var results = _domain.GetAllNews();

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results, typeof(IEnumerable<News>));
            Assert.AreEqual(4, results.Count());
        }

        [TestMethod]
        public void AreNewsAbstracts()
        {
            // Act
            var results = _domain.GetAllNews().ToList();

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results, typeof(IEnumerable<News>));
            Assert.IsTrue(results.All(i => i.Content.Length < 257));
            Assert.AreEqual(4, results.Count());
        }

        [TestMethod]
        public void GetNewsItem()
        {
            // Act
            var result = _domain.GetNewsItem("02");

            // Assert
            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(News));
            Assert.AreEqual("02", result.Id);
        }

        [TestMethod]
        public void GetTestimonials()
        {
            // Act
            var results = _domain.GetAllTestimonials();

            // Assert
            Assert.IsNotNull(results);
            Assert.IsInstanceOfType(results,typeof(IEnumerable<Testimonial>));
            Assert.AreEqual(3, results.Count());
        }

        #endregion
    }
}
